"""
校验器
"""

from utils.serializer_utils.deconstruct import deconstructible
from utils.serializer_utils.exceptions import DjangoValidationError

# 如果将这些值提供给 `validate()`，将触发 `self.required` 检查
EMPTY_VALUES = (None, "", [], (), {}, set())


@deconstructible
class BaseValidator:
    """ 校验器 基类 """

    message = "请确保该值为 %(limit_value)s（目前为 %(show_value)s）"
    code = "limit_value"

    def __init__(
        self,
        limit_value,
        message=None,
    ) -> None:
        self.limit_value = limit_value

        if message:
            self.message = message

    def __call__(self, value):
        cleaned = self.clean(value)
        limit_value = self.limit_value() if callable(self.limit_value) else self.limit_value
        params = {
            "limit_value": limit_value,
            "show_value": cleaned,
            "value": value,
        }

        if self.compare(cleaned, limit_value):
            raise DjangoValidationError(self.message, code=self.code, params=params)

    def __eq__(self, other) -> bool:
        return (
            isinstance(other, self.__class__)
            and self.limit_value == other.limit_value
            and self.message == other.message
            and self.code == other.code
        )

    def compare(self, a, b) -> bool:
        return a is not b

    def clean(self, x):
        return x


@deconstructible
class MaxValueValidator(BaseValidator):
    """ 最大值 校验器 """

    message = "请确保该值小于或等于 %(limit_value)s."
    code = "max_value"

    def compare(self, a, b) -> bool:
        return a > b


@deconstructible
class MinValueValidator(BaseValidator):
    """ 最小值 校验器 """

    message = "请确保该值大于或等于 %(limit_value)s"
    code = "min_value"

    def compare(self, a, b) -> bool:
        return a < b


@deconstructible
class MinLengthValidator(BaseValidator):
    """ 最小长度 校验器 """

    message = (
        "请确保该值至少有%(limit_value)d个字符（目前为%(show_value)d）个",
        "请确保该值至少有%(limit_value)d个字符（目前为%(show_value)d）个",
        "limit_value",
    )
    code = "min_length"

    def compare(self, a, b) -> bool:
        return a < b

    def clean(self, x):
        return len(x)


@deconstructible
class MaxLengthValidator(BaseValidator):
    """ 最大长度 校验器 """

    message = (
        "确保该值最多有 %(limit_value)d 个字符（目前为 %(show_value)d）个",
        "确保该值最多有 %(limit_value)d 个字符（目前为 %(show_value)d）个",
        "limit_value",
    )
    code = "max_length"

    def compare(self, a, b) -> bool:
        return a > b

    def clean(self, x):
        return len(x)


@deconstructible
class ProhibitNullCharactersValidator:
    """
    禁止空字符 验证器

    验证字符串不包含空字符
    """

    message = "不允许使用空字符"
    code = "null_characters_not_allowed"

    def __init__(
        self,
        message: str = None,
        code: str = None,
    ) -> None:
        if message is not None:
            self.message = message

        if code is not None:
            self.code = code

    def __call__(self, value):
        if "\x00" in str(value):
            raise DjangoValidationError(self.message, code=self.code)

    def __eq__(self, other) -> bool:
        return (
            isinstance(other, self.__class__)
            and self.message == other.message
            and self.code == other.code
        )
